package cn.cj.erp.serviceimpl.system;

import cn.cj.erp.common.utils.Convert;
import cn.cj.erp.dao.system.SysUserDao;
import cn.cj.erp.bo.system.SysDeptBo;
import cn.cj.erp.service.system.SysDeptService;
import cn.cj.erp.serviceimpl.base.ServiceImpl;
import cn.hutool.core.util.ObjectUtil;
import cn.cj.erp.common.constants.SystemConstants;
import cn.cj.erp.common.exception.ServiceException;
import cn.cj.erp.entity.system.SysDept;
import cn.cj.erp.dao.system.SysDeptDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 部门
 *
 * @author chenjian
 */
@Service
public class SysDeptServiceImpl extends ServiceImpl<SysDept, SysDeptBo> implements SysDeptService {
    @Resource
    private SysDeptDao sysDeptDao;
    @Resource
    private SysUserDao sysUserDao;

    @Override
    public SysDeptDao getBaseMapper() {
        return sysDeptDao;
    }

    @Override
    public SysDept convert2Entity(SysDeptBo sysDeptBo) {
        return Convert.convert(sysDeptBo, SysDept.class);
    }

    @Override
    public SysDeptBo convert2Bo(SysDept sysDept) {
        return Convert.convert(sysDept, SysDeptBo.class);
    }

    @Override
    public SysDeptBo getById(Long id) {
        SysDeptBo sysDeptBo = super.getById(id);
        if (!SystemConstants.TREE_ROOT.equals(sysDeptBo.getParentId())) {
            SysDeptBo parent = super.getById(sysDeptBo.getParentId());
            sysDeptBo.setParentName(parent.getName());
        }
        return sysDeptBo;
    }

    @Override
    public boolean save(SysDeptBo bo) {
        if (bo.getParentId() == null) {
            bo.setParentId(SystemConstants.TREE_ROOT);
        }
        bo.setParentIds(getParentIds(bo));
        return super.save(bo);
    }

    @Override
    public boolean updateById(SysDeptBo bo) {
        if (ObjectUtil.equals(bo.getDeptId(), bo.getParentId())) {
            throw new ServiceException("父部门不能是自己");
        }
        if (bo.getParentId() == null) {
            bo.setParentId(SystemConstants.TREE_ROOT);
        }
        bo.setParentIds(getParentIds(bo));
        return super.updateById(bo);
    }

    @Override
    public boolean removeById(Long deptId) {
        if (this.existChild(deptId)) {
            throw new ServiceException("存在下级部门");
        }
        if (sysUserDao.existByDeptId(deptId) > 0) {
            throw new ServiceException("部门存在用户");
        }
        return super.removeById(deptId);
    }

    @Override
    public List<SysDeptBo> queryTree(SysDeptBo params) {
        if (params.getParentId() == null) {
            params.setParentId(SystemConstants.TREE_ROOT);
        }
        List<SysDeptBo> list = super.queryList(params);
        return buildTree(list, params.getParentId(), params.getExcludeId());
    }

    @Override
    public Integer getCurrentUsedOrderNum(Long parentId) {
        Integer orderNum = getBaseMapper().getMaxOrderNum(parentId);
        if (ObjectUtil.isNull(orderNum)) {
            orderNum = 1;
        }
        return orderNum + 1;
    }

    @Override
    public boolean existChild(Long deptId) {
        return lambdaQuery().eq(SysDept::getParentId, deptId).count() > 0;
    }

    @Override
    public List<Long> listAllChildIds(Long deptId) {
        return getBaseMapper().listAllChildIds(deptId);
    }

    /**
     * 获取部门parentIds
     * @param bo 实体类
     */
    private String getParentIds(SysDeptBo bo) {
        if (ObjectUtil.isNull(bo)) {
            throw new ServiceException("部门为空");
        }
        if (bo.getParentId().equals(SystemConstants.TREE_ROOT)) {
            return SystemConstants.TREE_ROOT.toString();
        }
        SysDeptBo parent = super.getById(bo.getParentId());
        if (parent == null) {
            throw new ServiceException("父部门不存在");
        }
        return String.format("%s,%d", parent.getParentIds(), parent.getDeptId());
    }

    // ----------------------------------------------------------------
    /**
     * 构建部门树
     * @param list 部门列表
     * @param parentId 父节点ID
     * @param excludeId 要排除的ID
     * @return 树结构列表
     */
    public List<SysDeptBo> buildTree(List<SysDeptBo> list, Long parentId, Long excludeId) {
        List<SysDeptBo> returnList = new ArrayList<>();
        for (SysDeptBo dto : list) {
            // 排除的部门id不为空，且与当前id相同，则不处理
            if (excludeId != null && excludeId.equals(dto.getDeptId())) {
                continue;
            }
            // 如果是【顶级节点】, 遍历该父节点的所有子节点
            if (parentId.equals(dto.getParentId())) {
                recursionFn(list, dto);
                returnList.add(dto);
            }
        }
        if (returnList.isEmpty()) {
            return list;
        }
        return returnList;
    }

    /**
     * 递归部门列表，得到部门树
     * @param list 部门列表
     * @param current 当前部门
     */
    private void recursionFn(List<SysDeptBo> list, SysDeptBo current) {
        // 得到子节点列表
        List<SysDeptBo> childList = getChildList(list, current);
        current.setChildren(childList);
        for (SysDeptBo temp : childList) {
            if (hasChild(list, temp)) {
                recursionFn(list, temp);
            }
        }
    }

    /**
     * 得到子节点列表
     * @param list 部门列表
     * @param current 当前部门
     * @return 子节点列表
     */
    private static List<SysDeptBo> getChildList(List<SysDeptBo> list, SysDeptBo current) {
        List<SysDeptBo> childList = new ArrayList<>();
        for (SysDeptBo temp : list) {
            if (temp.getParentId().equals(current.getDeptId())) {
                childList.add(temp);
            }
        }
        return childList;
    }

    /**
     * 判断是否有子节点
     * @param list 部门列表
     * @param currentDept 当前部门
     * @return boolean
     */
    private boolean hasChild(List<SysDeptBo> list, SysDeptBo currentDept) {
        for (SysDeptBo temp : list) {
            if (temp.getParentId().equals(currentDept.getDeptId())) {
                return true;
            }
        }
        return false;
    }
}
